#pragma once
#include <iostream>
#include <string>
#include <strings.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include <unordered_map>
#include "Log.hpp"
using namespace std;

//可以当成函数指针
typedef std::function<string(const string &,const string &,uint16_t)> func_t;

Log lg;

enum{
    SOCKET_ERR=1,
    BIND_ERR
};


using namespace std;
const int size =1024; 
uint16_t defaultport=8080;
std::string defaultip="0.0.0.0";

class UdpServer
{
public:
    UdpServer(const uint16_t &port=defaultport,const string &ip=defaultip):sockfd_(0),port_(port),
    ip_(ip),Isrunning_(false)
    {}
    void Init()
    {
        //创建udp socket
        //
        sockfd_=socket(AF_INET,SOCK_DGRAM,0);
        if(sockfd_<0)
        {
            lg(Fatal,"sock creat erro,sockfd_ is:%d",sockfd_);
            exit(SOCKET_ERR);
        }
        lg(Info,"sock create success,sockfd_ is:%d",sockfd_);
        //2.blind_socket
        struct sockaddr_in lock;
        bzero(&lock,sizeof(lock));
        lock.sin_family=AF_INET;
        lock.sin_port=htons(port_);//需要保证我的端口号是网络字节序列，因为该端口号要给对方发送的
        lock.sin_addr.s_addr=inet_addr(ip_.c_str());//1. string -> uint32_t 2. uint32_t必须是网络序列的

        if(bind(sockfd_,(const struct sockaddr *)&lock,sizeof(lock))<0)
        {
            lg(Fatal,"bind erro,error: %d,err string:%s",errno,strerror(errno));
            exit(BIND_ERR);

        }
        // if(bind(sockfd_, (const struct sockaddr *)&lock, sizeof(lock)) < 0)
        // {
        //     lg(Fatal, "bind error, errno: %d, err string: %s", errno, strerror(errno));
        //     exit(BIND_ERR);
        // }

        lg(Fatal,"bind success,errno: %d,err string:%s",errno,strerror(errno));
    }
    void Run(func_t func)
    {
        Isrunning_=true;
        char inbuffer[size];
        while(Isrunning_)
        {
            struct sockaddr_in client;
            socklen_t len=sizeof(client);
            //收消息 从sockfd_读到inbuffer中去
            ssize_t n=recvfrom(sockfd_,inbuffer,sizeof(inbuffer)-1,0,(struct sockaddr*)&client,&len);
            if(n<0)
            {
                lg(Warning,"recvform error ,error:%d,err_string:%s",errno,strerror(errno));
                continue;
            }
            //
            inbuffer[n]=0;
            string info=inbuffer;
            string echo_string="server echo# "+info;
            uint16_t clientport=ntohs(client.sin_port);
            
            
        }
    }
    
    ~UdpServer()
    {
        if(sockfd_>0)   close(sockfd_);
    }
private:
    int sockfd_;//网络文件描述符
    std::string ip_;//
    bool Isrunning_;
    uint16_t port_;//表示服务器进程端口号    
};